package com.lvan.schedule.task;

import com.lvan.schedule.utils.SpringContextUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * Schedule Task Run Class
 */
public class SchedulingRunnable implements Runnable {

    private String beanName;
    private String methodName;
    private Object[] params;

    public SchedulingRunnable(String beanName, String methodName) {
        this.beanName = beanName;
        this.methodName = methodName;
    }

    public SchedulingRunnable(String beanName, String methodName, Object... params) {
        this.beanName = beanName;
        this.methodName = methodName;
        this.params = params;
    }

    @Override
    public void run() {
        try {
            Object bean = SpringContextUtils.getBean(beanName);

            Method method = null;
            if (params != null && params.length > 0) {
                Class<?>[] classes = new Class[params.length];
                for (int i = 0; i < params.length; i++) {
                    classes[i] = params[i].getClass();
                }
                method = bean.getClass().getDeclaredMethod(methodName, classes);
            } else {
                method = bean.getClass().getDeclaredMethod(methodName);
            }

            ReflectionUtils.makeAccessible(method);
            if (params != null && params.length > 0) {
                method.invoke(bean, params);
            } else {
                method.invoke(bean);
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        SchedulingRunnable runnable = (SchedulingRunnable) obj;
        if (params == null) {
            return beanName.equals(runnable.beanName)
                    && methodName.equals(runnable.methodName)
                    && runnable.params == null;
        }

        return beanName.equals(runnable.beanName)
                && methodName.equals(runnable.methodName)
                && Arrays.equals(params, runnable.params);
    }

    @Override
    public int hashCode() {
        if (params == null) {
            return Objects.hash(beanName, methodName);
        }
        return Objects.hash(beanName, methodName, Arrays.hashCode(params));
    }
}
